#include <stdexcept>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include "ServicePool.h"
#include "Trace.h"

namespace tsc
{
namespace common
{

/*******************************************************************************
 *
 * Constructor
 *
 ******************************************************************************/
ServicePool::ServicePool()
{
} // ServicePool::ServicePool

/*******************************************************************************
 *
 * Run services
 *
 ******************************************************************************/
void ServicePool::run()
{
  ENTER("ServicePool::run");

  // Wait for all threads in the pool to exit.
  for (std::size_t i = 0; i < mThreads.size(); ++i)
    mThreads[i]->join();

  RETURN;
} // ServicePool::run

/*******************************************************************************
 *
 * Stop services
 *
 ******************************************************************************/
void ServicePool::stop()
{
  ENTER("ServicePool::stop");

  // Explicitly stop all io_services.
  for (std::size_t i = 0; i < mIoServices.size(); ++i)
    mIoServices[i]->stop();

  RETURN;
} // ServicePool::stop

/*******************************************************************************
 *
 * Adds a new service to pool and returns the referance
 *
 ******************************************************************************/
boost::asio::io_service& ServicePool::getService()
{
  ENTER("ServicePool::getService");

  boost::thread* pThread = 0;
  boost::asio::io_service* pIoService = 0;
  boost::asio::io_service::work* pWork = 0;

  pIoService = new boost::asio::io_service();
  io_service_ptr service(pIoService);
  mIoServices.push_back(service);

  pWork = new boost::asio::io_service::work(*pIoService);
  work_ptr work(pWork);
  mWork.push_back(work);

  pThread = new boost::thread(boost::bind(&boost::asio::io_service::run,
                                          service));
  boost::shared_ptr<boost::thread> thread(pThread);
  mThreads.push_back(thread);

  RETURN(*service.get());
} // ServicePool::getService

/*******************************************************************************
 *
 * Adds a thread to pool
 *
 ******************************************************************************/
void ServicePool::addTread(boost::thread* pThread)
{
  ENTER("ServicePool::addThread");

  boost::shared_ptr<boost::thread> thread(pThread);
  mThreads.push_back(thread);

  RETURN;
} // ServicePool::addTread

} // namespace common
} // namespace tsc
